先前我們為了專注於 TypeScript 的使用方式,因此元件間的資料傳遞都是透過 props 進行。但隨著元件和功能越來越多,是不是開始覺得資料傳遞變得有些複雜了呢?為了避免 Props Drilling 的問題,今天我們要使用 useContext 和 useReducer 來優化目前的資料管理。
首先,在 src 資料夾下創建一個 store 資料夾,並在裡面新增 TodoContext.tsx 檔案。在現有的專案中,我們在 App.tsx 中匯出了 TodoItem 和 MessageDetails 型別供其他元件使用,現在我們將這些型別移到 TodoContext,統一在這個檔案中管理。
請將原本在 App.tsx 的 TodoItem 與 MessageDetails 型別複製過來:
export type TodoItem = {
id: number
title: string
isFinished: boolean
}
export type MessageDetails = {
visible: boolean
message: string
mode: 'error' | 'success'
}
刪除原先在這裡定義的 TodoItem 和 MessageDetails 型別,改為從 TodoContext.tsx 匯入:
import { type MessageDetails, type TodoItem } from './store/TodoContext'
更新型別匯入路徑:
import { type TodoItem } from '../store/TodoContext'
同樣地,更新型別匯入路徑:
import { type MessageDetails } from '../store/TodoContext'
接下來,我們在 TodoContext.tsx 中定義現有的新增和刪除功能的 action:
type ActionType =
| { type: 'ADD_TODO'; payload: string }
| { type: 'DELETE_TODO'; payload: number }
第一次看到這種寫法可能會覺得有點混亂。之前我們所提到的 Union 寫法不應該是這樣嗎:
type ActionType = { type: 'ADD_TODO'; payload: string } | { type: 'DELETE_TODO'; payload: number }
其實,這兩種寫法是完全等值的。在第一項內容前加上 | 是為了更好的排版,提升可讀性。像是使用 Prettier 這種程式碼格式化工具時,它也會自動為我們在第一行加上 |。
由於 useContext 和 useReducer 對於大多數 React 初學者來說,可能不像 useState 那麼熟悉,因此我們將優化的部分拆成兩篇。在下一篇文章中,我們將使用這兩個 hook 來優化我們的新增和刪除功能。